using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Text;

namespace Lyh.XianGuo.Reader.Common
{
    public class HttpClient
    {
        public CookieContainer Cookies = new CookieContainer();

        public HttpClient(CookieContainer cookieContainer)
        {
            Cookies = cookieContainer;
        }

        public HttpClient()
        {
        }

        private HttpWebResponse GetResponse(HttpParameter parameter)
        {
            HttpWebResponse httpWebResponse;
            try
            {
                ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertificate;

                var nameValueCollection = new NameValueCollection();
                if (!string.IsNullOrWhiteSpace(parameter.AcceptEncoding)) nameValueCollection.Add("Accept-Encoding", parameter.AcceptEncoding);
                if (!string.IsNullOrWhiteSpace(parameter.AcceptLanguage)) nameValueCollection.Add("Accept-Language", parameter.AcceptLanguage);
                if (!string.IsNullOrWhiteSpace(parameter.XRequestedWith)) nameValueCollection.Add("X-Requested-With", parameter.XRequestedWith);
                if (!string.IsNullOrWhiteSpace(parameter.Origin)) nameValueCollection.Add("Origin", parameter.Origin);

                var httpWebRequest = (HttpWebRequest) WebRequest.Create(parameter.Url);
                httpWebRequest.CookieContainer = Cookies;
                httpWebRequest.KeepAlive = parameter.KeepAlive;
                httpWebRequest.Method = parameter.Method.ToString();
                httpWebRequest.AllowAutoRedirect = parameter.AllowAutoRedirect;
                httpWebRequest.ContentType = parameter.ContentType;
                httpWebRequest.UserAgent = parameter.UserAgent;
                httpWebRequest.Accept = parameter.Accept;
                httpWebRequest.Timeout = parameter.Timeout;
                httpWebRequest.Referer = parameter.Referer;
                httpWebRequest.Headers.Add(nameValueCollection);
                if (parameter.Proxy != null) httpWebRequest.Proxy = parameter.Proxy;
                if (!string.IsNullOrWhiteSpace(parameter.Host)) httpWebRequest.Host = parameter.Host;

                if (parameter.Method == HttpMethod.POST && parameter.Data.Count>0)
                {
                    var data = CreateParameter(parameter.Data);
                    var bytes = parameter.Encoding.GetBytes(data);
                    httpWebRequest.ContentLength = bytes.Length;
                    var requestStream = httpWebRequest.GetRequestStream();
                    requestStream.Write(bytes, 0, bytes.Length);
                    requestStream.Close();
                }

                httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;
                if (httpWebResponse != null)
                {
                    if (httpWebResponse.Cookies.Count > 0)
                    {
                        Cookies.Add(httpWebResponse.Cookies);
                    }
                }
            }
            catch (WebException)
            {
                httpWebResponse = null;
            }
            return httpWebResponse;
        }

        private string GetString(HttpParameter parameter)
        {
            var result = string.Empty;
            var response = GetResponse(parameter);
            if (response == null) return result;
            var stream = response.GetResponseStream();
            if (stream == null) return result;
            if (response.ContentEncoding.ToLower().Contains("gzip"))
            {
                stream = new GZipStream(stream, CompressionMode.Decompress);
            }
            using (var streamReader = new StreamReader(stream, parameter.Encoding))
            {
                result = streamReader.ReadToEnd();
            }
            return result;
        }

        public string Request(HttpParameter parameter)
        {
            return GetString(parameter);
        }

        public Uri GetUri(HttpParameter parameter)
        {
            var response = GetResponse(parameter);
            return response.ResponseUri;
        }

        public byte[] GetImageBytes(HttpParameter parameter)
        {
            var response = GetResponse(parameter);
            var responseStream = response.GetResponseStream();
            var memoryStream = new MemoryStream();
            var array = new byte[4096];
            int count;
            if (responseStream == null) return new byte[0];
            while ((count = responseStream.Read(array, 0, array.Length)) > 0)
            {
                memoryStream.Write(array, 0, count);
            }
            return memoryStream.GetBuffer();
        }

        public Stream GetImageStream(HttpParameter parameter)
        {
            var response = GetResponse(parameter);
            if (response == null) return null;
            var responseStream = response.GetResponseStream();
            return responseStream;
        }

        public bool DownLoad(HttpParameter parameter)
        {
            var response = GetResponse(parameter);
            var responseStream = response.GetResponseStream();
            if (responseStream == null) return false;
            var fileStream = new FileStream(parameter.FileName, FileMode.Create);
            const int num = 2048;
            var buffer = new byte[num];
            var result = true;
            try
            {
                for (var i = responseStream.Read(buffer, 0, num); i > 0; i = responseStream.Read(buffer, 0, num))
                {
                    fileStream.Write(buffer, 0, i);
                }
                responseStream.Close();
                fileStream.Close();
                response.Close();
            }
            catch
            {
                result = false;
            }
            return result;
        }

        public List<Cookie> GetAllCookies()
        {
            var list = new List<Cookie>();
            var hashtable = (Hashtable) Cookies.GetType().InvokeMember("m_domainTable", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField, null, Cookies, new object[0]);
            foreach (var current in hashtable.Values)
            {
                var sortedList = (SortedList) current.GetType().InvokeMember("m_list", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField, null, current, new object[0]);
                foreach (CookieCollection cookieCollection in sortedList.Values)
                {
                    list.AddRange(cookieCollection.Cast<Cookie>());
                }
            }
            return list;
        }

        public static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            return true;
        }

        public string CreateParameter(IDictionary<string, string> parameters)
        {
            var buffer = new StringBuilder();
            foreach (var key in parameters.Keys)
            {
                buffer.AppendFormat("&{0}={1}", key, parameters[key]);
            }
            return buffer.ToString().TrimStart('&');
        }

    }
}
